/*!
 * \file WtHftStraDemo.cpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief WonderTrader HFT高频策略示例实现文件
 * 
 * \details 该文件实现了WtHftStraDemo类的完整功能，提供HFT高频策略的示例实现：
 *          
 *          核心算法逻辑：
 *          1. 理论价格计算：基于买卖盘量价加权平均计算理论价格
 *             理论价格 = (买一价×卖一量 + 卖一价×买一量) / (买一量 + 卖一量)
 *          2. 交易信号生成：
 *             - 理论价格 > 最新价：产生买入信号
 *             - 理论价格 < 最新价：产生卖出信号
 *          3. 订单管理：
 *             - 价格偏移：在理论价格基础上加减偏移量
 *             - 超时撤单：订单超过设定时间自动撤销
 *             - 频率控制：限制交易频率避免过度交易
 *          4. 风险控制：
 *             - 持仓限制：避免过度持仓
 *             - 预留资金：股票模式下预留部分资金
 *             - 通道监控：只在交易通道就绪时进行交易
 *          
 *          高频交易特性：
 *          - 毫秒级响应：每个Tick数据实时处理
 *          - 精确定价：基于微观市场结构的价格发现
 *          - 流动性提供：通过价格偏移提供市场流动性
 *          - 风险分散：快进快出降低市场风险暴露
 *          
 *          技术实现：
 *          - 线程安全：使用互斥锁保护订单集合
 *          - 内存管理：及时释放Tick数据防止内存泄漏
 *          - 异常处理：完善的错误检查和状态管理
 *          - 性能优化：减少不必要的计算和数据拷贝
 */

#include "WtHftStraDemo.h"
#include "../Includes/IHftStraCtx.h"

#include "../Includes/WTSVariant.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSContractInfo.hpp"
#include "../Share/TimeUtils.hpp"
#include "../Share/decimal.h"
#include "../Share/fmtlib.h"

extern const char* FACT_NAME;

/*!
 * \brief 构造函数
 * \param id 策略实例唯一标识符
 * 
 * \details 初始化HFT策略示例的所有成员变量：
 *          - 设置默认状态值
 *          - 初始化订单管理相关变量
 *          - 设置交易通道状态标志
 */
WtHftStraDemo::WtHftStraDemo(const char* id)
	: HftStrategy(id)
	, _last_tick(NULL)
	, _last_entry_time(UINT64_MAX)
	, _channel_ready(false)
	, _last_calc_time(0)
	, _stock(false)
	, _unit(1)
	, _cancel_cnt(0)
	, _reserved(0)
{
}

/*!
 * \brief 析构函数
 * 
 * \details 清理策略资源：
 *          - 释放最后一个Tick数据
 *          - 确保无内存泄漏
 */
WtHftStraDemo::~WtHftStraDemo()
{
	if (_last_tick)
		_last_tick->release();
}

/*!
 * \brief 获取策略名称
 * \return 策略名称字符串
 */
const char* WtHftStraDemo::getName()
{
	return "HftDemoStrategy";
}

/*!
 * \brief 获取策略工厂名称
 * \return 工厂名称字符串
 */
const char* WtHftStraDemo::getFactName()
{
	return FACT_NAME;
}

/*!
 * \brief 初始化策略参数
 * \param cfg 配置参数对象
 * \return 初始化成功返回true，失败返回false
 * 
 * \details 从配置文件中读取策略参数，这里演示一个外部参数配置的获取：
 *          - code: 交易标的代码
 *          - second: 订单超时时间（秒）
 *          - freq: 交易频率限制（毫秒）
 *          - offset: 价格偏移档数
 *          - reserve: 预留资金比例
 *          - stock: 是否为股票交易模式
 */
bool WtHftStraDemo::init(WTSVariant* cfg)
{
	// 这里演示一个外部配置参数的获取
	_code = cfg->getCString("code");
	_secs = cfg->getUInt32("second");
	_freq = cfg->getUInt32("freq");
	_offset = cfg->getUInt32("offset");
	_reserved = cfg->getDouble("reserve");

	_stock = cfg->getBoolean("stock");
	_unit = _stock ? 100 : 1;	// 股票交易单位100股，期货1手

	return true;
}

/*!
 * \brief 委托确认事件处理
 * \param localid 本地订单ID
 * \param bSuccess 是否成功
 * \param message 错误信息
 * \param userTag 用户标签
 * 
 * \details 处理订单委托确认，当前实现为空，可扩展处理委托失败情况
 */
void WtHftStraDemo::on_entrust(uint32_t localid, bool bSuccess, const char* message, const char* userTag)
{
	// 可扩展处理委托确认逻辑
}

/*!
 * \brief 策略初始化事件
 * \param ctx 策略上下文
 * 
 * \details 策略启动时调用，执行初始化操作：
 *          - 获取初始K线数据进行预热
 *          - 订阅Tick数据
 *          - 保存策略上下文引用
 */
void WtHftStraDemo::on_init(IHftStraCtx* ctx)
{
	// 获取历史K线数据进行策略预热
	// WTSTickSlice* ticks = ctx->stra_get_ticks(_code.c_str(), _count);
	// if (ticks)
	//     ticks->release();

	WTSKlineSlice* kline = ctx->stra_get_bars(_code.c_str(), "m1", 30);
	if (kline)
		kline->release();

	ctx->stra_sub_ticks(_code.c_str());

	_ctx = ctx;
}

/*!
 * \brief Tick数据事件处理
 * \param ctx 策略上下文
 * \param code 合约代码
 * \param newTick 新的Tick数据
 * 
 * \details 高频策略的核心逻辑，处理每个Tick数据：
 *          
 *          执行流程：
 *          1. 检查合约代码是否匹配
 *          2. 处理未完成订单状态
 *          3. 检查交易通道状态
 *          4. 计算理论价格
 *          5. 生成交易信号
 *          6. 执行交易决策
 *          
 *          理论价格算法：
 *          理论价格 = (买一价×卖一量 + 卖一价×买一量) / (买一量 + 卖一量)
 *          这个算法反映了市场的真实供需关系
 */
void WtHftStraDemo::on_tick(IHftStraCtx* ctx, const char* code, WTSTickData* newTick)
{	
	if (_code.compare(code) != 0)
		return;

	if (!_orders.empty())
	{
		check_orders();
		return;
	}

	if (!_channel_ready)
		return;

	WTSTickData* curTick = ctx->stra_get_last_tick(code);
	if (curTick)
		curTick->release();

	uint32_t curMin = newTick->actiontime() / 100000;	// actiontime是带毫秒的，要取得分钟，所以要除以10w
	if (curMin > _last_calc_time)
	{
		// 如果spread上次计算时间小于当前分钟，重新计算spread
		// WTSKlineSlice* kline = ctx->stra_get_bars(code, "m5", 30);
		// if (kline)
		//     kline->release();

		// 重新计算以后，更新记录时间
		_last_calc_time = curMin;
	}

	// 频率控制：防止过于频繁交易
	uint64_t now = TimeUtils::makeTime(ctx->stra_get_date(), ctx->stra_get_time() * 100000 + ctx->stra_get_secs());
	if(now - _last_entry_time <= _freq * 1000)
	{
		return;
	}

	int32_t signal = 0;
	double price = newTick->price();
	
	// 计算理论价格：基于买卖盘量价加权平均
	double pxInThry = (newTick->bidprice(0)*newTick->askqty(0) + newTick->askprice(0)*newTick->bidqty(0)) / (newTick->bidqty(0) + newTick->askqty(0));

	// 根据理论价格与最新价关系生成信号
	if (pxInThry > price)
	{
		// 买入信号：理论价格高于最新价
		signal = 1;
	}
	else if (pxInThry < price)
	{
		// 卖出信号：理论价格低于最新价
		signal = -1;
	}

	if (signal != 0)
	{
		double curPos = ctx->stra_get_position(code);
		curPos -= _reserved;	// 扣除预留资金

		WTSCommodityInfo* cInfo = ctx->stra_get_comminfo(code);

		if(signal > 0  && curPos <= 0)
		{
			// 买入信号，且当前持仓小于等于0
			// 最新价+偏移量下单
			double targetPx = price + cInfo->getPriceTick() * _offset;
			auto ids = ctx->stra_buy(code, targetPx, _unit, "enterlong");

			_mtx_ords.lock();
			for( auto localid : ids)
			{
				_orders.insert(localid);
			}
			_mtx_ords.unlock();
			_last_entry_time = now;
		}
		else if (signal < 0 && (curPos > 0 || ((!_stock || !decimal::eq(_reserved,0)) && curPos == 0)))
		{
			// 卖出信号，且当前持仓大于0，或者仓位为0但不是股票，或者仓位为0但是有预留资金
			// 最新价-偏移量下单
			double targetPx = price - cInfo->getPriceTick()*_offset;
			auto ids = ctx->stra_sell(code, targetPx, _unit, "entershort");

			_mtx_ords.lock();
			for (auto localid : ids)
			{
				_orders.insert(localid);
			}
			_mtx_ords.unlock();
			_last_entry_time = now;
		}
	}
}

/*!
 * \brief 检查订单状态
 * 
 * \details 定期检查未完成订单的状态：
 *          - 超时订单自动撤销：防止订单长时间挂单
 *          - 更新撤单计数器：统计撤单次数
 *          - 线程安全操作：使用互斥锁保护订单集合
 */
void WtHftStraDemo::check_orders()
{
	if (!_orders.empty() && _last_entry_time != UINT64_MAX)
	{
		uint64_t now = TimeUtils::makeTime(_ctx->stra_get_date(), _ctx->stra_get_time() * 100000 + _ctx->stra_get_secs());
		if (now - _last_entry_time >= _secs * 1000)	// 超过设定时间没有成交的，撤单
		{
			_mtx_ords.lock();
			for (auto localid : _orders)
			{
				_ctx->stra_cancel(localid);
				_cancel_cnt++;
				_ctx->stra_log_info(fmt::format("Order expired, cancelcnt updated to {}", _cancel_cnt).c_str());
			}
			_mtx_ords.unlock();
		}
	}
}

/*!
 * \brief K线数据事件处理
 * \param ctx 策略上下文
 * \param code 合约代码
 * \param period K线周期
 * \param times 时间戳
 * \param newBar 新的K线数据
 * 
 * \details 处理K线更新事件，当前实现为空，可扩展技术指标计算等功能
 */
void WtHftStraDemo::on_bar(IHftStraCtx* ctx, const char* code, const char* period, uint32_t times, WTSBarStruct* newBar)
{
	// 可扩展K线数据处理逻辑
}

/*!
 * \brief 成交事件处理
 * \param ctx 策略上下文
 * \param localid 本地订单ID
 * \param stdCode 标准合约代码
 * \param isBuy 是否买入
 * \param qty 成交数量
 * \param price 成交价格
 * \param userTag 用户标签
 * 
 * \details 处理订单成交回报，当前实现为空，可扩展成交统计和盈亏计算
 */
void WtHftStraDemo::on_trade(IHftStraCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double qty, double price, const char* userTag)
{
	// 可扩展成交处理逻辑
}

/*!
 * \brief 持仓变化事件处理
 * \param ctx 策略上下文
 * \param stdCode 标准合约代码
 * \param isLong 是否多头
 * \param prevol 之前持仓量
 * \param preavail 之前可用量
 * \param newvol 新持仓量
 * \param newavail 新可用量
 * 
 * \details 处理持仓变化通知，当前实现为空，可扩展持仓管理逻辑
 */
void WtHftStraDemo::on_position(IHftStraCtx* ctx, const char* stdCode, bool isLong, double prevol, double preavail, double newvol, double newavail)
{
	// 可扩展持仓变化处理逻辑
}

/*!
 * \brief 订单状态事件处理
 * \param ctx 策略上下文
 * \param localid 本地订单ID
 * \param stdCode 标准合约代码
 * \param isBuy 是否买入
 * \param totalQty 总数量
 * \param leftQty 剩余数量
 * \param price 订单价格
 * \param isCanceled 是否已撤销
 * \param userTag 用户标签
 * 
 * \details 处理订单状态变化：
 *          - 跟踪本策略提交的订单
 *          - 处理订单撤销和完全成交情况
 *          - 维护活跃订单集合
 *          - 更新撤单计数器
 */
void WtHftStraDemo::on_order(IHftStraCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double totalQty, double leftQty, double price, bool isCanceled, const char* userTag)
{
	// 如果订单不是我们发出去的订单，就忽略掉
	auto it = _orders.find(localid);
	if (it == _orders.end())
		return;

	// 如果已撤销，或者剩余数量为0，就清除原有的id记录
	if(isCanceled || leftQty == 0)
	{
		_mtx_ords.lock();
		_orders.erase(it);
		if (_cancel_cnt > 0)
		{
			_cancel_cnt--;
			_ctx->stra_log_info(fmt::format("cancelcnt -> {}", _cancel_cnt).c_str());
		}
		_mtx_ords.unlock();
	}
}

/*!
 * \brief 交易通道就绪事件
 * \param ctx 策略上下文
 * 
 * \details 处理交易通道连接成功：
 *          - 检查是否有未完成的订单
 *          - 撤销所有未完成订单避免异常状态
 *          - 设置通道就绪标志
 *          - 更新撤单计数器
 */
void WtHftStraDemo::on_channel_ready(IHftStraCtx* ctx)
{
	double undone = _ctx->stra_get_undone(_code.c_str());
	if (!decimal::eq(undone, 0) && _orders.empty())
	{
		// 这说明有未完成的订单在记录之外，先撤掉
		_ctx->stra_log_info(fmt::format("{}中有不在跟踪中的未完成订单 {} 手，全部撤销", _code, undone).c_str());

		bool isBuy = (undone > 0);
		OrderIDs ids = _ctx->stra_cancel(_code.c_str(), isBuy, undone);
		for (auto localid : ids)
		{
			_orders.insert(localid);
		}
		_cancel_cnt += ids.size();

		_ctx->stra_log_info(fmt::format("cancelcnt -> {}", _cancel_cnt).c_str());
	}

	_channel_ready = true;
}

/*!
 * \brief 交易通道断开事件
 * \param ctx 策略上下文
 * 
 * \details 处理交易通道连接断开：
 *          - 设置通道断开标志
 *          - 停止新订单提交
 *          - 等待通道恢复
 */
void WtHftStraDemo::on_channel_lost(IHftStraCtx* ctx)
{
	_channel_ready = false;
}